package plp.imperative2.memory;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

import plp.expressions2.memory.IdentificadorJaDeclaradoException;
import plp.expressions2.memory.IdentificadorNaoDeclaradoException;
import plp.imperative1.command.Comando;
import plp.imperative1.memory.EntradaVaziaException;
import plp.imperative2.declaration.DefRendezvous;
import plp.imperative2.declaration.ListaDeclaracaoParametro;

public class Rendezvous {

	private ListaDeclaracaoParametro parametrosFormais;

	private Comando comando;

	private Queue<ExecucaoRendezvous> filaExecucao = new ConcurrentLinkedQueue<ExecucaoRendezvous>();

	public Rendezvous(ListaDeclaracaoParametro parametrosFormais,
			DefRendezvous parametro2) {
		this.parametrosFormais = parametrosFormais;
		this.comando = parametro2.getComando();
	}

	public void executar() throws IdentificadorJaDeclaradoException,
			IdentificadorNaoDeclaradoException, EntradaVaziaException,
			InterruptedException {
		while (this.filaExecucao.size() == 0)
			Thread.yield();
		synchronized (this.filaExecucao) {
			ExecucaoRendezvous execucao = this.filaExecucao.poll();
			comando.executar(execucao.getAmbiente());
			execucao.finish();
		}
	}

	public ListaDeclaracaoParametro getParametrosFormais() {
		return parametrosFormais;
	}

	public Comando getComando() {
		return comando;
	}

	public ExecucaoRendezvous enqueue(AmbienteExecucaoImperativa2 ambiente) {
		synchronized (this.filaExecucao) {
			ExecucaoRendezvous execucao = new ExecucaoRendezvous(ambiente);
			this.filaExecucao.add(execucao);
			return execucao;
		}
	}

	public class ExecucaoRendezvous {
		private AmbienteExecucaoImperativa2 ambiente;
		private boolean finished;

		protected ExecucaoRendezvous(AmbienteExecucaoImperativa2 ambiente) {
			this.ambiente = ambiente;
		}

		public boolean isFinished() {
			return finished;
		}

		protected void finish() {
			this.finished = true;
		}

		public AmbienteExecucaoImperativa2 getAmbiente() {
			return ambiente;
		}

	}
}
